package com.dashboard.domain;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.BeforeClass;
import org.junit.Test;

import com.dashboard.util.tests.BDUtils;
import com.dashboard.util.tests.PropertyTestsUtils;

/**
 * Testa os cálculos possíveis de cálculo contábil. Árvore em questão:
 * 
 * Unidade Operacional Tim
 * 
 * A(-120)(500)
 * 		B (40)(300)
 * 			C (-30)(100)
 * 			D (70)(200)
 * 		E (-160)(200)
 * 			F (120)(400)
 * 			G (-80)(-50)
 * 			H (-200)(-150)
 * 
 * Unidade Operacional Oi
 * 
 * A(495)(0)
 * 		B (110)(-70)
 * 			C (300)(-50)
 * 			D (-190)(-20)
 * 		E (385)(70)
 * 			F (510)(-10)
 * 			G (-175)(30)
 * 			H (50)(50)
 * 
 * Unidade Operacional Vivo
 * 
 * A(14)(30)
 * 		B (-60)(60)
 * 			C (140)(20)
 * 			D (-200)(40)
 * 		E (74)(-30)
 * 			F (-300)(-10)
 * 			G (230)(-40)
 * 			H (144)(20)
 * 
 * Unidade Operacional Consolidada
 * 
 * A(389)(530)
 * 		B (90)(290)
 * 			C (410)(70)
 * 			D (-320)(220)
 * 		E (299)(240)
 * 			F (330)(380)
 * 			G (-25)(-60)
 * 			H (-6)(-80)
 * 
 * @author João Neves
 * 
 */
public class CalculoContabilLeituraTest
{

	private static final String LOCAL_ARQ = "datasets/dre/";

	private static BDUtils bdUtils;
	private static EntityManager entityManager;
	private static Map<Object, Object> substituicoesDados;
	
	private static final long CALCULO_CONTABIL_ID_C_OI = 164;
	private static final long CALCULO_CONTABIL_ID_B_OI = 163;
	private static final long CALCULO_CONTABIL_ID_A_OI = 162;
	private static final long CALCULO_CONTABIL_ID_A_TIM = 154;
	private static final long CALCULO_CONTABIL_ID_A_VIVO = 170;
	private static final long CALCULO_CONTABIL_ID_H_VIVO = 177;
	private static final long CALCULO_CONTABIL_ID_E_VIVO = 174;
	private static final long CALCULO_CONTABIL_ID_F_CONSOLIDADO = 151;
	private static final long CALCULO_CONTABIL_ID_E_CONSOLIDADO = 150;
	private static final long CALCULO_CONTABIL_ID_A_CONSOLIDADO = 146;
	private static final long CALCULO_CONTABIL_ID_G_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS = 184;
	private static final long CALCULO_CONTABIL_ID_B_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS = 179;
	private static final long CALCULO_CONTABIL_ID_A_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS = 178;
	private CalculoContabil calculoContabilCOi;
	private CalculoContabil calculoContabilBOi;
	private CalculoContabil calculoContabilAOi;
	private CalculoContabil calculoContabilATim;
	private CalculoContabil calculoContabilAVivo;
	private CalculoContabil calculoContabilHVivo;
	private CalculoContabil calculoContabilEVivo;
	private CalculoContabil calculoContabilFConsolidado;
	private CalculoContabil calculoContabilEConsolidado;
	private CalculoContabil calculoContabilAConsolidado;
	private CalculoContabil calculoContabilGConsolidadoSemUoNaoConsolidadas;
	private CalculoContabil calculoContabilBConsolidadoSemUoNaoConsolidadas;
	private CalculoContabil calculoContabilAConsolidadoSemUoNaoConsolidadas;
	
	
	/**
	 * Prepara a execução de todos os testes.
	 * 
	 * @throws Exception
	 *             - Se algo sair errado.
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		EntityManagerFactory emf = Persistence.createEntityManagerFactory(
			PropertyTestsUtils.getProperty("persistenceUnit.name"));
		entityManager = emf.createEntityManager();

		substituicoesDados = new HashMap<Object, Object>();
		substituicoesDados.put("[NULL]", null);
		
		bdUtils = BDUtils.getInstance();
		bdUtils.setUpBeforeClass(LOCAL_ARQ + "DreDadosIniciais.xml", substituicoesDados);
		
		bdUtils.setUp();
	}

	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil folha e não consolidado.
	 */
	@Test
	public void testCalculaValorFolhaNaoConsolidado()
	{
		calculoContabilCOi = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_C_OI);
		final Float VALOR_ORCADO = 300.0f;
		final Float VALOR_REAL = -50.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilCOi.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilCOi.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos folhas e não consolidado. 
	 */
	@Test
	public void testCalculaValorFilhosFolhasNaoConsolidado()
	{
		calculoContabilBOi = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_B_OI);
		final Float VALOR_ORCADO = 110.0f;
		final Float VALOR_REAL = -70.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilBOi.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilBOi.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e não consolidado.
	 * 
	 * UO Oi
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasNaoConsolidadoOi()
	{
		calculoContabilAOi = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_OI);
		final Float VALOR_ORCADO = 495.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilAOi.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAOi.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e não consolidado.
	 * 
	 * UO Tim
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasNaoConsolidadoTim()
	{
		calculoContabilATim = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_TIM);
		final Float VALOR_ORCADO = -120.0f;
		final Float VALOR_REAL = 500.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilATim.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilATim.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e não consolidado.
	 * 
	 * UO Vivo
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasNaoConsolidadoVivo()
	{
		calculoContabilAVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_VIVO);
		final Float VALOR_ORCADO = 14.0f;
		final Float VALOR_REAL = 30.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilAVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil folha e consolidado.
	 */
	@Test
	public void testCalculaValorFolhaConsolidado()
	{
		calculoContabilFConsolidado 
			= entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_F_CONSOLIDADO);
		final Float VALOR_ORCADO = 330.0f;
		final Float VALOR_REAL = 380.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilFConsolidado.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilFConsolidado.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos folhas e consolidado. 
	 */
	@Test
	public void testCalculaValorFilhosFolhasConsolidado()
	{
		calculoContabilEConsolidado 
			= entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_E_CONSOLIDADO);
		final Float VALOR_ORCADO = 299.0f;
		final Float VALOR_REAL = 240.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilEConsolidado.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilEConsolidado.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e consolidado.
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasConsolidado()
	{
		calculoContabilAConsolidado 
			= entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_CONSOLIDADO);
		final Float VALOR_ORCADO = 389.0f;
		final Float VALOR_REAL = 530.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilAConsolidado.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAConsolidado.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil folha e consolidado sem unidades
	 * operacionais não-consolidadas. 
	 */
	@Test
	public void testCalculaValorFolhaConsolidadoSemUnidadesOperacionais()
	{
		calculoContabilGConsolidadoSemUoNaoConsolidadas = entityManager.find(
			CalculoContabil.class, CALCULO_CONTABIL_ID_G_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2010;
		assertEquals(VALOR_ORCADO, calculoContabilGConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilGConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil com filhos folhas e consolidado sem 
	 * unidades operacionais não-consolidadas. 
	 */
	@Test
	public void testCalculaValorFilhosFolhasConsolidadoSemUnidadesOperacionais()
	{
		calculoContabilBConsolidadoSemUoNaoConsolidadas = entityManager.find(
			CalculoContabil.class, CALCULO_CONTABIL_ID_B_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2010;
		assertEquals(VALOR_ORCADO, calculoContabilBConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilBConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil com filhos não-folhas e consolidado sem 
	 * unidades operacionais não-consolidadas. 
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasConsolidadoSemUnidadesOperacionais()
	{
		calculoContabilAConsolidadoSemUoNaoConsolidadas = entityManager.find(
			CalculoContabil.class, CALCULO_CONTABIL_ID_A_CONSOLIDADO_SEM_UO_NAO_CONSOLIDADAS);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2012;
		assertEquals(VALOR_ORCADO, calculoContabilAConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAConsolidadoSemUoNaoConsolidadas.getCalculo(
			MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil folha e não consolidado, quando o mês
	 * não está relacionado à nenhum valor.
	 */
	@Test
	public void testCalculaValorFolhaNaoConsolidadoMesSemValor()
	{
		calculoContabilHVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_H_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilHVivo.getCalculo(MesEnum.MARCO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilHVivo.getCalculo(MesEnum.OUTUBRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo Contábil folha e não consolidado, quando o ano
	 * não está relacionado à nenhum valor.
	 */
	@Test
	public void testCalculaValorFolhaNaoConsolidadoAnoSemValor()
	{
		calculoContabilHVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_H_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2005;
		assertEquals(VALOR_ORCADO, calculoContabilHVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilHVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos folhas e não consolidado, 
	 * quando o mês não está relacionado à nenhum valor. 
	 */
	@Test
	public void testCalculaValorFilhosFolhasNaoConsolidadoMesSemValor()
	{
		calculoContabilEVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_E_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilEVivo.getCalculo(MesEnum.FEVEREIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilEVivo.getCalculo(MesEnum.JULHO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos folhas e não consolidado, 
	 * quando o ano não está relacionado à nenhum valor.
	 */
	@Test
	public void testCalculaValorFilhosFolhasNaoConsolidadoAnoSemValor()
	{
		calculoContabilEVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_E_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2020;
		assertEquals(VALOR_ORCADO, calculoContabilEVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilEVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e não consolidado, 
	 * quando o mês não está relacionado à nenhum valor.
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasNaoConsolidadoMesSemValor()
	{
		calculoContabilAVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 2009;
		assertEquals(VALOR_ORCADO, calculoContabilAVivo.getCalculo(MesEnum.ABRIL, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAVivo.getCalculo(MesEnum.SETEMBRO, ANO).getValorReal());
	}
	
	/**
	 * Testa os cálculos real e orçado do Valor de Cálculo não folha com filhos não folhas e não consolidado, 
	 * quando o ano não está relacionado à nenhum valor.
	 */
	@Test
	public void testCalculaValorFilhosNaoFolhasNaoConsolidadoAnoSemValor()
	{
		calculoContabilAVivo = entityManager.find(CalculoContabil.class, CALCULO_CONTABIL_ID_A_VIVO);
		final Float VALOR_ORCADO = 0.0f;
		final Float VALOR_REAL = 0.0f;
		final Integer ANO = 1998;
		assertEquals(VALOR_ORCADO, calculoContabilAVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorOrcado());
		assertEquals(VALOR_REAL, calculoContabilAVivo.getCalculo(MesEnum.JANEIRO, ANO).getValorReal());
	}
}